
// Yadan @Thingslink 
// Socket 
// esp8266
// Author Zack
// Version V0.5.1.210417

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoJson.h>
#include <EEPROM.h>        //EEPROM
#include "SimpleDHT.h"
#include <Ticker.h>

Ticker flipper;

//DHT11传感器有关
int pinDHT11 = D3;                  //IO0
SimpleDHT11 dht11(pinDHT11);
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
byte isReadTH = 0;

//Wifi 有关
const char* ssid = "";            // WIFI名和密码
const char* password = "";
ESP8266WebServer server(80);       // 以下 String html = "  "; 是网页部分
//socket client
WiFiClient espClient;                                                         // 定义wifiClient实例
char wifiConnLoopi = 0;

const char* client_id = "";                   // 标识当前设备的客户端编号
const char* client_pwd = "";
String cid = client_id;


bool connect_wifi = false;
const char *host = "sip.iot.open.thingslink.com";//"192.168.43.157";
const int port = 5081;


char CmdList[10][60];
char SensorLisr[4][50];


struct config_type
{
  char stassid[32];
  char stapsw[64];
  char clientid[20];
  char clientpwd[20];
};
config_type config;


long lastMsg = 0;                                                               // 记录上一次发送信息的时长

String prepareHtmlPage() {
  String htmlPage =
    String("") +
    "<!DOCTYPE html> <html>\n" +
    "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n" +
    "<title>Ya Dan Device</title>\n" +
    "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n" +
    "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n" +
    ".button {display: block;width: 120px;background-color: #1abc9c;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n" +
    ".button-on {background-color: #5AD2FF;}\n" +
    ".button-on:active {background-color: #DE341E;}\n" +

    ".button-off {background-color: #34495e;}\n" +
    ".button-off:active {background-color: #DE341E;}\n" +
    "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n" +
    "</style>\n" +
    "</head>\n" +
    "<body>\n" +
    "<h1>Ya Dan Device </h1>\n" +
    "<h3>Server Connected: " + String(espClient.connected() ? "OK" : "NO") + "----Light(PIN2): " + String(digitalRead(2) == 0 ? "ON" : "OFF") + "</h3>\n" +
    "<h3>Temperature: " + String(temperature) + "----Humidity: " + String(humidity) + "</h3>\n" +

    "<a id='F1' href='./pin?light1=1'><input class='button button-on' type='submit' value='ON' ></a><br>" +
    "<a id='F2' href='./pin?light1=0'><input class='button button-off' type='submit' value='OFF' ></a><br>" +
    "<a id='F3' href='./setting'>Go to setting device.</a><br>" +

    "</html>" +
    "\r\n";
  return htmlPage;
}
String settingHtmlPage() {
  String settingHtml = "<html><head><title>Ya Dan Device Setting</title><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0'><script>function submit(){var ssid=document.getElementById('SSID').value;var password=document.getElementById('password').value;var clientid=document.getElementById('clientid').value;var clientpwd=document.getElementById('clientpwd').value;window.open('./setting/do?ssid='+ssid+'&clientid='+clientid+'&clientpwd='+clientpwd+'&password='+password,'_top');}</script><style>input{height:30px;margin-left:10px;}body{margin:auto;text-align:center;font:18px;line-height:40px;}button{width:35%;}</style></head><body><div ><br/><p style='font-size: 30px;color:blue'>Ya Dan Device Setting</p><br>SSID:<input id='SSID' type='text' placeholder='Wifi Name' value='" + String(config.stassid) + "'/><br>Password:<input id='password'  type='password' placeholder=' Key in password' value='" + String(config.stapsw) + "'/><br>ClientID:<input id='clientid' type='text' placeholder='client id'  value='" + String(config.clientid) + "'/><br>ClientPWD:<input id='clientpwd' type='text' placeholder='client password'  value='" + String(config.clientpwd) + "'/><br><button onclick='submit()'> submit</button> <br><a href='/'>Go To Control Page!</a></div></body></html>";
  return settingHtml;
}
/*
   保存参数到EEPROM
*/
void saveConfig()
{
  Serial.println("Save config!");
  Serial.print("stassid:");
  Serial.println(config.stassid);
  Serial.print("stapsw:");
  Serial.println(config.stapsw);
  Serial.print("client id:");
  Serial.println(config.clientid);
  Serial.print("client password:");
  Serial.println(config.clientpwd);

  EEPROM.begin(1024);
  uint8_t *p = (uint8_t*)(&config);
  for (int i = 0; i < sizeof(config); i++)
  {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
}

/*
   从EEPROM加载参数
*/
void loadConfig()
{
  EEPROM.begin(1024);
  uint8_t *p = (uint8_t*)(&config);
  for (int i = 0; i < sizeof(config); i++)
  {
    *(p + i) = EEPROM.read(i);
  }
  EEPROM.commit();
  Serial.println("-----Read config-----");
  Serial.print("stassid:");
  Serial.println(config.stassid);
  Serial.print("stapsw:");
  Serial.println(config.stapsw);
  Serial.print("client id:");
  Serial.println(config.clientid);
  Serial.print("client password:");
  Serial.println(config.clientpwd);
}




void pin() {
  if (server.arg("light1") == "1") {
    digitalWrite(2, LOW);   // 2端口
    Serial.println("2-0");
    server.send(200, "text/html", prepareHtmlPage());
  }
  else if (server.arg("light1") == "0") {
    digitalWrite(2, HIGH);
    Serial.println("2-1");
    server.send(200, "text/html", prepareHtmlPage());
  }
}

void setting() {
  Serial.println(WiFi.status());
  Serial.println(WL_CONNECTED);

  ssid = server.arg("ssid").c_str();
  password = server.arg("password").c_str();

  client_id = server.arg("clientid").c_str();
  client_pwd = server.arg("clientpwd").c_str();

  strcpy(config.stassid, ssid);
  strcpy(config.stapsw, password);
  strcpy(config.clientid, client_id);
  strcpy(config.clientpwd, client_pwd);
  saveConfig();
  server.send(200, "text/html", settingHtmlPage());
  delay(200);
  WiFi.disconnect();
}

void handleRoot() {
  server.send(200, "text/html", prepareHtmlPage());
}

void settingPage() {
  server.send(200, "text/html", settingHtmlPage());
}


void setup(void) {                  //定义端口号16，4，5，2，14，12，13，15，0
  pinMode(2, OUTPUT);
  Serial.begin(115200);

  //flipper.attach(2, getTempAndHum);

  loadConfig(); //读取账号和密码
  WiFi.mode(WIFI_AP_STA);
  //WIFI模块的STA模式和AP模式有什么区别:AP是接入点，可以让用户接入。STA--Station无线终端，不接受无线接入，可以连接到无线AP，无线网卡工作在STA下

  // 设置内网
  IPAddress softLocal(192, 168, 128, 1); // 1 设置内网WIFI IP地址
  IPAddress softGateway(192, 168, 128, 1);
  IPAddress softSubnet(255, 255, 255, 0);
  WiFi.softAPConfig(softLocal, softGateway, softSubnet);

  String apName = ("Yadan_" + (String)ESP.getChipId()); // 2 设置WIFI名称
  const char *softAPName = apName.c_str();
  WiFi.softAP(softAPName, "adminadmin");      // 3创建wifi  名称 +密码 adminadmin

  IPAddress myIP = WiFi.softAPIP();  // 4输出创建的WIFI IP地址
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  Serial.print("softAPName: ");  // 5输出WIFI 名称
  Serial.println(apName);



  server.on("/", handleRoot);
  server.on("/setting", settingPage);
  server.on("/pin", HTTP_GET, pin);
  server.on("/setting/do", HTTP_GET, setting);
  server.begin();
}



void reconnect() {
  if (!espClient.connected()) {
    //while (!client.connected()) {
    Serial.print("Attempting  connection...");
    // Attempt to connect
    if (espClient.connect(host, port)) {
      Serial.println("connected");
      // 连接成功时订阅主题
      char buf[1] = {0x01};
      espClient.write(buf, 1);
      // socket connect
      cid=config.clientid;
      String str = "Command=Login\r\nClientID=" + cid;
      sendStringCommand(str);
    } else {
      Serial.print("failed, rc=");
      Serial.println("wait connection.to server ......");
      Serial.println(" try again in 1 seconds");
      // Wait 1 seconds before retrying
      delay(1000);
    }
  }
}

void loop(void) {
  server.handleClient();
  if (WiFi.status() == WL_CONNECTED) {
    if (!espClient.connected()) {
      reconnect();
    }
  }
  else {
    if (wifiConnLoopi == 0)
    {
      WiFi.begin(config.stassid, config.stapsw);   // 以下是串口监视器显示内容。
    }
    //Serial.println(WiFi.status());

    if (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print("..");
      wifiConnLoopi = wifiConnLoopi + 1;
      if (wifiConnLoopi > 10) {
        wifiConnLoopi = 0;

      }
    } else {
      Serial.printf("\nConnecting to %s\nIP Address : %s\n", ssid, WiFi.localIP().toString().c_str());
    }

  }



  if (espClient.connected())//当处于链接状态 时
  {
    size_t len = espClient.available();
    if (len > 0) //如果缓冲区字符串大于0
    {
      uint8_t rbuf[len];
      //透传数据
      uint8_t c = espClient.read(rbuf, len);

      //espClient.write(rbuf,sizeof(rbuf));
      if (len > 4)
      {
        long rlength = rbuf[3] << 24 | rbuf[2] << 16 | rbuf[1] << 8 | rbuf[0];
        //Serial.println(rlength);
        long rclength = rbuf[7] << 24 | rbuf[6] << 16 | rbuf[5] << 8 | rbuf[4];
        //Serial.println(rclength);
        char commBuf[rclength + 1];
        char* cmdBuf;
        for (int i = 0; i < rclength; i++) {
          commBuf[i] = rbuf[i + 8];
        }
        commBuf[rclength] = '\0';
        String commStr = String(commBuf);
        cmdParse(commBuf);
        String commadContent = getCommandValue("Command");
        Serial.println("parse:" + commadContent);

        if (commadContent.equals("Login"))
        {
          Serial.println("Login success:" + commadContent);
        }
        else if (commadContent.equals("Route"))
        {

          String itemcontent = getCommandValue("Item");
          Serial.println(itemcontent);
          String sensorID = sensorParse(itemcontent, "SensorID");
          String value = sensorParse(itemcontent, "Value");

          if (sensorID == "1" && (value == "1" || value == "true")) {
            digitalWrite(2, 1);
          } else if (sensorID == "1" && (value == "0" || value == "false")) {
            digitalWrite(2, 0);
          }

          String str = "Command=Route\r\nClientID=\r\nItem=" + itemcontent;
          sendStringCommand(str);

        }
      }
    }
  }

}

String getCommandValue(String spl)
{
  String result;
  int i = sizeof(CmdList) / sizeof(CmdList[0]);
  for (int j = 0; j < i; j++)
  {
    String tempStr = CmdList[j];
    if ( spl.equals(tempStr))
    {
      return String(CmdList[j + 1]);
    }
  }

  return result;

}

void cmdParse(char* str)
{
  char dst[5][100];
  int ii = split(dst, str, "\r\n");
  for (int i = 0; i < ii; i++) {
    char dst2[2][100];
    int iii = split(dst2, dst[i], "=");
    for (int j = 0; j < 2; j++)
    {
      strcpy(CmdList[j + 2 * i], dst2[j]);
    }
  }

}


String sensorParse(String str, const String spl)
{
  char dst[5][100];
  String result;
  char* schar = const_cast<char *>(str.c_str());
  int ii = split(dst, schar, ";");
  for (int i = 0; i < ii; i++) {
    // Serial.println(dst[i]);
    char dst2[2][100];
    int iii = split(dst2, dst[i], ":");
    if (String(dst2[0]) == spl)
    {
      return String(dst2[1]);
    }
  }

  return result;
}

int split(char dst[][100], char* str, const char* spl)
{
  int n = 0;
  char* result = NULL;
  char *p;
  char* stringList;
  //strcpy(stringList, str);
  result = strtok_r(str, spl, &p);
  while (result != NULL)
  {
    strcpy(dst[n++], result);
    result = strtok_r(NULL, spl, &p);
  }
  return n;
}

void sendStringCommand(String str)
{
  int sendLength = 0;
  long lenStr = str.length();

  long totalLenStr = lenStr + 4;
  char loopi = 0;
  char sendSizeBuf[4];
  for (loopi = 0; loopi < 4; loopi++)
  {
    sendSizeBuf[loopi] = (char)(totalLenStr >> (loopi * 8) & 0xff);
  }
  espClient.write(sendSizeBuf, 4);
  for (loopi = 0; loopi < 4; loopi++)
  {
    sendSizeBuf[loopi] = (char)(lenStr >> (loopi * 8) & 0xff);

  }
  espClient.write(sendSizeBuf, 4);
  espClient.write(str.c_str(), lenStr);

}
